//
// Created by LiuYou on 2021/10/20.
//

#include <iostream>
#include <unistd.h>
#include <cstring>
#include <sys/wait.h>


static const int LEFT = 30000000;
static const int RIGHT = 30000200;


/**
 * @brief
 * @details 用 201 个子进程来计算这 201 个待计算的任务。
 * 那就是每次产生一个待计算的 i 值, 我就马上 fork(); 把这个 i 扔给子进程。
 *
 *
 *
 * @param argc
 * @param argv
 * @return
 */
/*
    wait, waitpid, waitid - wait for process to change state.(等待进程状态发生变化。)

       // wstatus: 进程状态。要的是整形的地址, 你别真给它一个整形的地址, 其实很多函数都是要一个指针, 一个二级指针,
       // 要的未必是一个指针值, 要的是一个什么样的地址。所以必须结合man手册查看这个参数的详细情况和注意事项。
       // 这里 wstatus 要的是一个整形变量的地址值, 你要实实在在给它一块内存空间, 给它一个指针可以吗? 可以。但是
       // 指针必须指向一个内存空间。这个函数来回填这块空间中的内容。
       // If wstatus is not NULL, wait() and waitpid() store status information in the int to which it points.
       // This integer can be inspected with the  following macros (which take the integer itself as an argument,
       // not a pointer to it, as is done in wait() and waitpid()!):
       // 如果 wstatus 不是 NULL，wait() 和 waitpid() 将状态信息存储在它指向的 int 中(即回填)。
       // 可以使用以下宏检查这个整数（它们将整数本身作为参数，而不是指向它的指针，就像在 wait() 和 waitpid() 中所做的那样！）:

        WIFEXITED(wstatus) (wait if exited)
              returns true if the child terminated normally, that is, by calling exit(3) or _exit(2), or by returning from main().
              如果子进程正常终止，即通过调用 exit(3) 或 _exit(2)，或者从 main() 返回，则返回 true。
              exit(3)指的是库函数, 而_exit(2)指的是系统调用。

       WEXITSTATUS(wstatus) (wait exit status)
              returns the exit status of the child.  This consists of the least significant 8 bits of the status argument that the child specified in a call
              to exit(3) or _exit(2) or as the argument for a return statement in main().  This macro should be employed only if WIFEXITED returned true.
              返回孩子的退出状态。这由子进程在调用 exit(3) 或 _exit(2)
              或作为 main() 中 return 语句的参数指定的状态参数的最低有效 8 位组成。仅当 WIFEXITED 返回 true 时才应使用此宏。

       WIFSIGNALED(wstatus)
              returns true if the child process was terminated by a signal.
              如果子进程被信号终止，则返回 true。

       WTERMSIG(wstatus)
              returns the number of the signal that caused the child process to terminate.  This macro should be employed only if WIFSIGNALED returned true.
              返回导致子进程终止的信号编号。仅当 WIFSIGNALED 返回 true 时才应使用此宏。

       WCOREDUMP(wstatus)
              returns true if the child produced a core dump (see core(5)).  This macro should be employed only if WIFSIGNALED returned true.
              如果子进程产生了核心转储，则返回 true（请参阅 core(5)）。仅当 WIFSIGNALED 返回 true 时才应使用此宏。

              This macro is not specified in POSIX.1-2001 and is not available on some UNIX implementations (e.g., AIX, SunOS).  Therefore, enclose its  use
              inside #ifdef WCOREDUMP ... #endif.
              此宏未在 POSIX.1-2001 中指定，并且在某些 UNIX 实现（例如 AIX、SunOS）上不可用。因此，将它的用法包含在 ifdef WCOREDUMP ... endif 中。

       WIFSTOPPED(wstatus)
              returns  true if the child process was stopped by delivery of a signal; this is possible only if the call was done using WUNTRACED or when the
              child is being traced (see ptrace(2)).
              如果子进程因传递信号而停止，则返回 true；仅当调用是使用 WUNTRACED 完成或正在跟踪孩子时才可能这样做（请参阅 ptrace(2)）。

       WSTOPSIG(wstatus)
              returns the number of the signal which caused the child to stop.  This macro should be employed only if WIFSTOPPED returned true.
              返回导致孩子停止的信号的编号。仅当 WIFSTOPPED 返回 true 时才应使用此宏。

       WIFCONTINUED(wstatus)
              (since Linux 2.6.10) returns true if the child process was resumed by delivery of SIGCONT.
              （自 Linux 2.6.10 起）如果子进程通过传递 SIGCONT 恢复，则返回 true。

       // wait();收尸, 收回来是谁的尸是不知道的。我们只能收尸, 通过返回值才知道收的是谁的尸。
       pid_t wait(int *wstatus);

       // waitpid(); 可以指定收谁的尸。waitpid();真正好用的地方是 options 参数。
       // wait();是死等, 阻塞的。而waitpid();的options参数的设计可以避免死等。

       The value of options is an OR of zero or more of the following constants:
       options 的值是以下零个或多个常量的 OR: (options是一个位图)

       WNOHANG (wait no hang)    return immediately if no child has exited.
       如果没有孩子退出，立即返回。这是options中最好用的一个。
       如果当前没有任何的子进程退出的话,  如果你在调用waitpid();时options加入了 WNOHANG 选项的话, 那我也立马退出。
       如果指定了 WNOHANG 选项, 其实就相当于把waitpid();由阻塞变为了非阻塞。
       如果你指定了 WNOHANG , 你指定收哪个PID的尸, 原来的wait操作是这样的: 死等死等, 收一个尸就返回了。而waitpid是
       收尸, 一看还在正常运行, 我也马上走人。如果我一收尸, 这个子进程也确实结束了, 那就收尸成功了。

       WUNTRACED (wait untraced)  also  return  if  a  child has stopped (but not traced via ptrace(2)).  Status for traced children which have stopped is provided even if
                   this option is not specified.

       WCONTINUED (wait continued) (since Linux 2.6.10)
                   also return if a stopped child has been resumed by delivery of SIGCONT.

       The value of pid can be:

       < -1   meaning wait for any child process whose process group ID is equal to the absolute value of pid.
       意思是等待进程组 ID 等于 pid 绝对值的任何子进程。


       -1     meaning wait for any child process.
       意思是等待任何子进程。
       收任何一个子进程的尸。
       wait(&status); 就相当于 waitpid(-1, &status, 0);

       0      meaning wait for any child process whose process group ID is equal to that of the calling process at the time of the call to waitpid().
       这意味着等待在调用 waitpid() 时其进程组 ID 等于调用进程组 ID 的任何子进程。
       收同组当中的任意一个子进程的尸。

       > 0    meaning wait for the child whose process ID is equal to the value of pid.
       意思是等待进程 ID 等于 pid 值的子进程。
       收为pid的子进程的尸。


       pid_t waitpid(pid_t pid, int *wstatus, int options);

       int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
                       / * This is the glibc and POSIX interface; see
                          NOTES for information on the raw system call. * /

 RETURN VALUE
       wait(): on success, returns the process ID of the terminated child; on error, -1 is returned.
       // wait(): 成功时，返回终止子进程的进程 ID；出错时，返回-1。

       waitpid():  on success, returns the process ID of the child whose state has changed; if WNOHANG was specified and one or more child(ren) specified by
       pid exist, but have not yet changed state, then 0 is returned.  On error, -1 is returned.

       waitid(): returns 0 on success or if WNOHANG was specified and no child(ren) specified by id has yet changed state; on error, -1 is returned.

       Each of these calls sets errno to an appropriate value in the case of an error.


*/

int main(int argc, char** argv) {
    int mark{};
    for (int i = LEFT; i <= RIGHT; ++i) {

        pid_t pid = fork();
        if (pid < 0) {
            perror( "fork()" );
            exit( 1 );
        }
        if (pid == 0) {
            mark = 1;
            for (int j = 2; j < i / 2; ++j) {
                if (i % j == 0) {
                    mark = 0;
                    break;
                }
            }
            if (mark == 1) {
                printf( "%d 是一个质数。\n", i );
            }
            exit( 0 );
        }

    }

    int status;
    for (int i = LEFT; i <= RIGHT; ++i) {
//        waitpid();
//        wait( &status );
        // todo 笔记: 如果不关心子进程的状态, 那么直接将参数指定为 nullptr即可。
        wait( nullptr );
    }

    return 0;
}
